/***********************************************************************************
 * 文件名： mcu_adc.c
 * 作者： 刘言
 * 版本： 1
 * 说明：
 * 		ADC驱动。
 * 修改记录：
 * 	2024/9/7: 初版。 刘言。
***********************************************************************************/
#include "mcu_adc.h"

#if _ADC_CLK_DIV == 0
    #define ADC_DIV_VALUE   1
#elif _ADC_CLK_DIV == 1
    #define ADC_DIV_VALUE   2
#elif _ADC_CLK_DIV == 2
    #define ADC_DIV_VALUE   4
#elif _ADC_CLK_DIV == 3
    #define ADC_DIV_VALUE   8
#elif _ADC_CLK_DIV == 4
    #define ADC_DIV_VALUE   16
#elif _ADC_CLK_DIV == 5
    #define ADC_DIV_VALUE   32
#elif _ADC_CLK_DIV == 6
    #define ADC_DIV_VALUE   64
#endif

#define F_ADC   (F_PCLK / ADC_DIV_VALUE)
#define ADC_CAL_DELAY_US  ((4 * 1000000 / F_ADC) + 1)
#define ADC_EN_DELAY_US  ((8 * 1000000 / F_ADC) + 1)

#define _ADC_OVRMOD     1   // 当过载发生时，ADC_DR 寄存器会被上一次转换结果覆盖掉
#define _ADC_CONT       0   // 单次扫描转换模式
#define _ADC_EOCIE      1   // 1: 使能转换结束中断，扫描时每个通道转换结束都会触发一次
#define _ADC_EOSEQIE    1   // 1: 使能序列结束中断，所有使能的通道都扫描转换完毕了

// #define ADC_CR_BITS_PROPERTY_RS            (ADC_CR_ADCAL | ADC_CR_ADSTP | ADC_CR_ADSTART | ADC_CR_ADDIS | ADC_CR_ADEN) /* ADC register CR bits with HW property "rs": Software can read as well as set this bit. Writing '0' has no effect on the bit value. */




static adc_result_callback_t mRCb = NULL;


void Adc_Init()
{
    ADC1->CFGR2 = (_ADC_CLK_SOURCE << 31) | (_ADC_CLK_DIV << 28);   
    ADC1->CFGR1 = (_ADC_OVRMOD << 12) | (_ADC_CONT << 13) | (_ADC_WAIT << 14);
    ADC1->SMPR = (_ADC_SMP << 0);
    ADC1->CHSELR = _ADC_CHSEL;

#if (_ADC_EN)
    ADC1_COMMON->CCR = (1 << 22) | (1 << 23);
#endif

    ADC1->IER = (_ADC_EOCIE << 2) | (_ADC_EOSEQIE << 3);

    // MODIFY_REG(ADC1->CR,ADC_CR_BITS_PROPERTY_RS,ADC_CR_ADCAL);
    ADC1->CR = ADC_CR_ADCAL;     // 开始校准ADC
    while(((adc_cr_bits_t *)&ADC1->CR)->ADCAL); // 等待校准完毕
    Mcu_Delayus(ADC_CAL_DELAY_US);
    
#if (_ADC_EN)
    ADC1->CR = ADC_CR_ADEN;      // 使能ADC
    Mcu_Delayus(ADC_EN_DELAY_US);
#endif
    NVIC_SetPriority(ADC_COMP_IRQn, 0);
    NVIC_EnableIRQ(ADC_COMP_IRQn);
}

void Adc_StartScan(adc_result_callback_t cb)
{
    while(((adc_cr_bits_t *)&ADC1->CR)->ADSTART);   // 等待上次序列转换结束
    mRCb = cb;
    ADC1->CR = ADC_CR_ADSTART;  // 开始转换， 序列转换结束后硬件清零
}

void Adc_SetScanChSel(u32 ch_sel)
{
    bool adc_st = false;
    if(((adc_cr_bits_t *)&ADC1->CR)->ADEN)
    {
        adc_st = true;
        Adc_Disable();
    }
    ADC1->CHSELR = ch_sel;
    if(adc_st)
    {
        Adc_Enable();
    }
}

void Adc_Disable()
{
    if(((adc_cr_bits_t *)&ADC1->CR)->ADEN)
    {
        while(((adc_cr_bits_t *)&ADC1->CR)->ADSTART);   // 等待上次序列转换结束
        ADC1_COMMON->CCR = 0;   // 关闭VREF和温度传感器
        ADC1->CR = ADC_CR_ADDIS;    // 开始失能ADC
        while(((adc_cr_bits_t *)&ADC1->CR)->ADEN);  // 等待失能ADC完毕
    }
}

void Adc_Enable()
{
    ADC1_COMMON->CCR = (1 << 22) | (1 << 23);
    ADC1->CR = ADC_CR_ADEN;      // 使能ADC
    Mcu_Delayus(ADC_EN_DELAY_US);
}


IN_LINE void Adc_EvIrqHander()
{
    if(((adc_isr_bits_t *)&ADC1->ISR)->EOC) // 一次ADC转换结束，读取ADC_DR自动清零
    {
        if(mRCb)mRCb(ADC1->DR);
    }
    // if(((adc_isr_bits_t *)&ADC1->ISR)->EOSEQ)   // 一次扫描结束
    // {

    // }
    ADC1->ISR = 0XFF;   // 清零所有标志位
}


